﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using BlackBBS.Infrastructure.TelnetProtocol;
using BlackBBS.Infrastructure.Logging;
using BlackBBS.Infrastructure.Repository;
using BlackBBS.Models.Data;
using BlackBBS.Enums;
using System.Net;
using BlackBBS.Helpers;

namespace BlackBBS
{
    /// <summary>
    /// This is connected Telnet connection spawned off the server
    /// </summary>
    public class Connection
    {
        private TelnetClient _client = null;

        public ILogger Logger { get; set; }
        public IServerRepository Repository { get; set; }
        public Session Session { get; set; }
        public ConfigSettings ServerSettings { get; set; }
        public int Node { get; set; }

        /// <summary>
        /// Read only Connections Client Socket Handle (port client is being served on)
        /// </summary>
        public IntPtr ClientSocketHandle
        {
            get
            {
                return this._client.Socket.Handle;
            }
        }

        /// <summary>
        /// Read only Connections Client Remote End Point (connections remote details
        /// </summary>
        public EndPoint ClientRemoteEndPoint
        {
            get
            {
                return this._client.Socket.RemoteEndPoint;
            }
        }

        public Connection(Socket socket, int node)
        {
            this.Node = node;

            this.Session = new Session
            {
                Node = this.Node,
                CurrentArea = Area.LogOn
            };
            this.Session.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Session_PropertyChanged);
            this._client = new TelnetClient(socket, this.Node);
            this._client.Connect();
            this._client.OnDisconnect += new TelnetEventHandler(_client_OnDisconnect);
            this._client.OnSent += new TelnetEventHandler(_client_OnSent);
            this._client.OnException += new TelnetErrorEventHandler(_client_OnException);
        }

        public void Connect()
        {
            this.Logger.Debug(string.Format("Client {0}, joined", this._client.Socket.RemoteEndPoint));

            var menu = new BlackBBS.Menus.LogOn
            {
                Connection = this
            };            
            menu.Init();
            menu.SendMenu();
        }

        public void SetCurrentArea(Area area)
        {
            this.Session.CurrentArea = area;
        }

        void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            var session = sender as Session;
            if (session.Id > 0)
            {
                this.Repository.Sessions.Save(session);
            }
        }

        public void SendPressAnyKeyToContinue()
        {
            this._client.SendANSITemplateString(TelnetClient.MessageTemplate, MessageStrings.AnyKeyToContinue);
        }

        public void SendInvalidKey(string value)
        {
            this._client.SendANSITemplateString(TelnetClient.MessageTemplate, string.Format(MessageStrings.InvalidKeyPressed, value));
            this._client.Pause(1);
        }

        public void Pause(int interval, int duration = 1000)
        {
            this._client.Pause(interval, duration);
        }

        public void SendString(string message, bool suppressCarriageReturn = true)
        {
            this._client.SendString(message, suppressCarriageReturn);
        }

        public void SendTemplate(string template, string message, bool waitForAnyKey = false)
        {
            this._client.SendANSITemplateString(template, message, waitForAnyKey);
        }

        public void ClearScreen()
        {
            this._client.ClearScreen();
        }

        public void SendFile(string filename)
        {
            this._client.SendFile(this.ServerSettings.MenuFullPath(filename));
        }

        public Dictionary<string, string> SendScript(string filename)
        {
            return this._client.SendScript(this.ServerSettings.MenuFullPath(filename), this.ServerSettings.ScriptVariableIndicator);
        }

        public string GetResponse(string message, string inputColor = null, string defaultValue = null)
        {
            var response = this._client.SendAndWaitForEnter(inputColor + message + ANSIColorHelper.ResetToDefault());
            response = string.IsNullOrEmpty(response) ? null : response;
            return response ?? defaultValue;
        }

        // Disconnect the client
        public void Disconnect()
        {
            this._client.Dispose();
            this.Repository.Sessions.Delete(this.Session.Id);
        }

        // Send the shutdown message first then Disconnect the client
        public void Shutdown()
        {
            this._client.SendString("** Server Shutting Down! **");
            this.Disconnect();
        }

        void _client_OnException(object sender, TelnetErrorArgs e)
        {
            this.Logger.Error(e.Exception);
        }

        void _client_OnSent(object sender, TelnetEventArgs e)
        {

        }

        void _client_OnDisconnect(object sender, TelnetEventArgs e)
        {
            
        }
    }
}
